package com.rw.tool.util.basic;

import java.io.Serializable;
import java.util.Iterator;
import java.util.RandomAccess;

/**
 * 位数组
 */
public class BitArray implements RandomAccess, Serializable, Iterable<Boolean> {
    /**
     * 除以8的移数
     */
    private static final int DIV_BY_EIGHT_SHIFT = 3;

    /**
     * 模8的掩码
     */
    private static final int MOD_BY_EIGHT_AND = 0b111;

    /**
     * 保存的字节数组
     */
    private final byte[] byteArr;

    /**
     * 保存的位数
     */
    private final int size;

    /**
     * 声明一个bit数组
     *
     * @param size 数组长度
     */
    public BitArray(int size) {
        // 字节数组长度是 size / 8 向上取整
        int length = (int) Math.ceil((float) size / Byte.SIZE);

        this.byteArr = new byte[length];
        this.size = size;
    }


    /**
     * 声明一个bit数组
     *
     * @param byteArray 声明的字节数组
     */
    public BitArray(byte[] byteArray) {
        // 如果溢出
        if (byteArray.length > Integer.MAX_VALUE >> DIV_BY_EIGHT_SHIFT) {
            throw new ArrayIndexOutOfBoundsException("byteArray.length * 8 can not greater than Integer.MAX_VALUE");
        }
        // size是 length * 8
        this.size = byteArray.length << DIV_BY_EIGHT_SHIFT;

        this.byteArr = byteArray;
    }

    /**
     * 声明一个bit数组
     *
     * @param size      位数长度
     * @param byteArray 声明的字节数组
     */
    public BitArray(byte[] byteArray, int size) {
        // size 不能大于 byteArray.length * 8
        if (size >> DIV_BY_EIGHT_SHIFT > byteArray.length) {
            String errorMsg = "size can not greater than byteArray.length * 8!";
            throw new IllegalArgumentException(errorMsg);
        }

        this.byteArr = byteArray;
        this.size = size;
    }

    /**
     * 位数组长度
     */
    public int size() {
        return this.size;
    }

    /**
     * 获取第index位的二进制
     * 并把这个二进制转为byte
     * byte只会等于0或1
     *
     * @param index 位置
     * @return 二进制字节
     */
    public byte getBitNum(int index) {
        assertSize(index);

        int position = index >> DIV_BY_EIGHT_SHIFT;
        int mod = index & MOD_BY_EIGHT_AND;

        return ByteUtil.getBitNum(byteArr[position], mod);
    }

    /**
     * 检查index是否在合理范围内
     *
     * @param index 位置
     */
    private void assertSize(int index) {
        if (index >= size) {
            throw new ArrayIndexOutOfBoundsException(index);
        }
    }

    /**
     * 获取第index位的二进制
     *
     * @param index 位置
     * @return 二进制
     */
    public boolean hasBit(int index) {
        assertSize(index);

        int position = index >> DIV_BY_EIGHT_SHIFT;
        int mod = index & MOD_BY_EIGHT_AND;

        return ByteUtil.hasBit(byteArr[position], mod);
    }

    /**
     * 设置index位的二进制
     *
     * @param index 位置
     * @param value 值
     */
    public void setBit(int index, byte value) {
        assertSize(index);

        int position = index >> DIV_BY_EIGHT_SHIFT;
        int mod = index & MOD_BY_EIGHT_AND;

        byteArr[position] = ByteUtil.setBit(byteArr[position], mod, value);
    }

    /**
     * 设置index位的二进制
     *
     * @param index 位置
     * @param value 值
     */
    public void setBit(int index, boolean value) {
        assertSize(index);

        int position = index >> DIV_BY_EIGHT_SHIFT;
        int mod = index & MOD_BY_EIGHT_AND;

        byteArr[position] = ByteUtil.setBit(byteArr[position], mod, value);
    }

    /**
     * 直接操作字节数组
     * 获得字节数组的某个字节
     *
     * @param index 位置
     * @return 对应的字节
     */
    public byte getRawByte(int index) {
        assertSize(index);

        return byteArr[index];
    }

    /**
     * 直接操作字节数组
     * 设置字节数组的某个字节
     *
     * @param index 位置
     * @param value 值
     */
    public void setRawByte(int index, byte value) {
        assertSize(index);

        byteArr[index] = value;
    }

    /**
     * 获得字节数组
     *
     * @return 字节数组
     */
    public byte[] getByteArray() {
        return byteArr;
    }

    /**
     * 迭代器
     */
    @Override
    public Iterator<Boolean> iterator() {
        return new BitArrayIterator(byteArr, size);
    }
}